/* NewbieContest : IrcCaesar solver 
 * by RaX| <raxxx.fr@gmail.com>
 *
 * This is a free software distribued as-is.
 */

#include <iostream>
#include <sstream>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERV_ADDR "195.225.204.21"
#define SERV_PORT 6667

class NbSocket
{

public:

  NbSocket (char*, int);
  virtual ~NbSocket (void);

  std::string read_socket (void);
  void write_socket (char*);

private:

  int m_socket;
  struct sockaddr_in irc_sock;

};

std::string caesar_decode (char *, int);

int
main (void)
{

  NbSocket::NbSocket sock (SERV_ADDR, SERV_PORT); 

  while (true)
   {
    std::string str;

    str = sock.read_socket ();
    
    if (str.rfind ("*** No Ident response") != std::string::npos)
     {
     
      sock.write_socket ("USER Guest luna * RaX\n");
      sock.write_socket ("NICK raxou\n");
      sock.write_socket ("PRIVMSG Daneel :.challenge_caesar start\n");
     
     }
   else if (str.rfind ("PRIVMSG raxou :") != std::string::npos)
    {

     char decode_str [12];
     memset (&decode_str, 0, sizeof (decode_str));

     //int y = str.find_last_of (":") + 1;
     int y = str.length () - 12;
     strncpy ((char *)&decode_str, (const char*)str.c_str () + y, 10);
 
     std::stringstream response;

     response << "PRIVMSG Daneel :.challenge_caesar "\
              << caesar_decode (decode_str, 3)\
	      << std::endl;

     sock.write_socket ((char*)response.str ().c_str ());
     //std::cout << "\e[0;32m" << decode_str << "\e[0m" << std::endl;
     
    }

    std::cout << "\e[0;31m" << str << "\e[0m" << std::endl;
   
    if (str.rfind ("PRIVMSG raxou :Félicitations !") != std::string::npos)
      break;

   }

  return EXIT_SUCCESS;

}

std::string
caesar_decode (char *str, int key)
{

  std::string tab = "abcdefghijklmnopqrstuvwxyz";
  std::string decoded;

  unsigned int a;
  int k = 26-key;

  while (k < 0)
    k += 26;

  while ( k > 25)
    k -= 26;

  for (unsigned int i = 0; i < strlen (str); i++)
   {
    a = tab.find (str[i]);
    if (a != std::string::npos)
      decoded += tab.c_str ()[(a + k > 25) ? a + k - 26 : a + k];
   }

  return decoded;

}

NbSocket::NbSocket (char *ip_addr, int port)
{

  struct sockaddr_in irc_sock;

  irc_sock.sin_addr.s_addr = inet_addr (ip_addr);
  irc_sock.sin_family = AF_INET;
  irc_sock.sin_port = htons (port);

  m_socket = socket (AF_INET, SOCK_STREAM, 0);
  if (m_socket == 0)
   {
     std::cerr << "Unable to create socket" << std::endl;
     exit (EXIT_FAILURE);
   }

  if (connect (m_socket, (const sockaddr*) &irc_sock, sizeof (irc_sock)) == -1)
   {
    std::cerr << "Failed to connect" << std::endl;
    exit (EXIT_FAILURE);
   }

}

std::string
NbSocket::read_socket (void)
{

  char received [512];

  memset (&received, 0, sizeof (received));
  read (m_socket, &received, sizeof (received));

  return std::string (received);

}

void
NbSocket::write_socket (char *message)
{

  write (m_socket, message, strlen (message));

}

NbSocket::~NbSocket (void)
{

  close (m_socket);

}

